unit uMaterialFont;

interface
uses
  Classes,
  GlContext, GlRenderContextInfo, GlColor, GlMaterial, GLScene, glcanvas,
  VectorGeometry,
  GLBitmapFont, GlCrossPlatform;
type
  TMaterialFont = class(TGLBitmapFont)
  public
    fMaterial: TGLMaterial;
    procedure RenderString(var rci : TRenderContextInfo;
                            const aString : AnsiString; alignment : TAlignment;
                            layout : TGLTextLayout; const color : TColorVector;
                            position : PVector = nil; reverseY : Boolean = False); override;
  end;
implementation
uses
  GlState, OpenGl1x;
  
  procedure TMaterialFont.RenderString(var rci : TRenderContextInfo;
              const aString : AnsiString; alignment : TAlignment;
              layout : TGLTextLayout; const color : TColorVector; position : PVector = nil;
              reverseY : Boolean = False);

     function AlignmentAdjustement(p : Integer) : Single;
     var
        i : Integer;
     begin
        i:=0;
        while (p<=Length(aString)) and (aString[p]<>#13) do begin
           Inc(p); Inc(i);
        end;
        case alignment of
           taLeftJustify : Result:=0;
           taRightJustify : Result:=-CalcStringWidth(Copy(aString, p-i, i))
        else // taCenter
            Result:=Round(-CalcStringWidth(Copy(aString, p-i, i))*0.5);
        end;
     end;

     function LayoutAdjustement : Single;
     var
        i, n : Integer;
     begin
        n:=1;
        for i:=1 to Length(aString) do
           if aString[i]=#13 then Inc(n);
        case TGLTextLayout(layout) of
           tlTop : Result:=0;
           tlBottom : Result:=(n*(CharHeight+VSpace)-VSpace);
        else // tlCenter
           Result:=Round((n*(CharHeight+VSpace)-VSpace)*0.5);
        end;
     end;

  var
     i : Integer;
     topLeft, bottomRight : TTexPoint;
     vTopLeft, vBottomRight : TVector;
     deltaH, deltaV, spaceDeltaH : Single;
     currentChar : AnsiChar;
  begin
     if (Glyphs.Width=0) or (aString='') then Exit;
     PrepareImage;
     PrepareParams(rci);
     // prepare texture if necessary
     // precalcs
     if Assigned(position) then
        MakePoint(vTopLeft, position[0]+AlignmentAdjustement(1), position[1]+LayoutAdjustement, 0)
     else MakePoint(vTopLeft, AlignmentAdjustement(1),  LayoutAdjustement, 0);
     deltaV:=-(CharHeight+VSpace);
     if reverseY then
        vBottomRight[1]:=vTopLeft[1]+CharHeight
     else vBottomRight[1]:=vTopLeft[1]-CharHeight;
     vBottomRight[2]:=0;
     vBottomRight[3]:=1;
     spaceDeltaH:=GetCharWidth(#32)+HSpaceFix+HSpace;
     // set states
    glEnable(GL_TEXTURE_2D);
     rci.GLStates.Disable(stLighting);
     //rci.GLStates.Enable(stBlend);
     //rci.GLStates.SetGLCurrentTexture(0, GL_TEXTURE_2D, FTextureHandle.Handle);
     fMaterial.Apply(rci);
     //rci.GLStates.TextureBinding[0, ttTexture2d] := FTextureHandle.Handle;
     //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
     // start rendering
     //rci.GLStates.PushAttrib([sttCurrent]);
     glColor4fv(@color);
     glBegin(GL_QUADS);
     for i:=1 to Length(aString) do begin
        currentChar:=aString[i];
        case currentChar of
           #0..#12, #14..#31 : ; // ignore
           #13 : begin
              if Assigned(position) then
                 vTopLeft[0]:=position[0]+AlignmentAdjustement(i+1)
              else vTopLeft[0]:=AlignmentAdjustement(i+1);
              vTopLeft[1]:=vTopLeft[1]+deltaV;
              if reverseY then
                 vBottomRight[1]:=vTopLeft[1]+CharHeight
              else vBottomRight[1]:=vTopLeft[1]-CharHeight;
           end;
           #32 : vTopLeft[0]:=vTopLeft[0]+spaceDeltaH;
        else
           deltaH:=GetCharWidth(currentChar);
           if deltaH>0 then begin
              GetCharTexCoords(currentChar, topLeft, bottomRight);
              vBottomRight[0]:=vTopLeft[0]+deltaH;

              glTexCoord2fv(@topLeft);
              glVertex4fv(@vTopLeft);

              glTexCoord2f(topLeft.S, bottomRight.T);
              glVertex2f(vTopLeft[0], vBottomRight[1]);

              glTexCoord2fv(@bottomRight);
              glVertex4fv(@vBottomRight);

              glTexCoord2f(bottomRight.S, topLeft.T);
              glVertex2f(vBottomRight[0], vTopLeft[1]);

              vTopLeft[0]:=vTopLeft[0]+deltaH+HSpace;
           end;
        end;
     end;
     glEnd;
     //rci.GLStates.PopAttrib;
     // unbind texture
     //rci.GLStates.SetGLCurrentTexture(0, GL_TEXTURE_2D, 0);
     fMaterial.UnApply(rci);
  //   rci.GLStates.TextureBinding[0, ttTexture2d] := 0;
     //rci.GLStates.ResetGLCurrentTexture;
  end;

end.
